package com.cinc.ebc.mm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cinc.ebc.mm.constant.StockTransferStatus;
import com.cinc.ebc.mm.entity.*;
import com.cinc.ebc.mm.mapper.MmStockTransferDetailMapper;
import com.cinc.ebc.mm.mapper.MmStockTransferMapper;
import com.cinc.ebc.mm.model.MmMaterialStockAllocateModel;
import com.cinc.ebc.mm.model.MmStockTransferDetailModel;
import com.cinc.ebc.mm.service.IMmMaterialStockService;
import com.cinc.ebc.mm.service.IMmStockInOutService;
import com.cinc.ebc.mm.service.IMmStockTransferService;
import com.cinc.ebc.mm.vo.MmStockTransferDetailPage;
import com.cinc.mdm.constant.MdmConstant;
import com.cinc.mdm.modules.codeRule.service.IMdmCodeRuleService;
import com.cinc.mdm.modules.movementType.service.IMdmMovementTypeService;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.UUIDGenerator;
import org.jeecg.common.util.oConvertUtils;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: 库存调拨
 * @Author: jeecg-boot
 * @Date: 2022-06-21
 * @Version: V1.0
 */
@Service
public class MmStockTransferServiceImpl extends ServiceImpl<MmStockTransferMapper, MmStockTransfer> implements IMmStockTransferService {

    @Autowired
    private MmStockTransferMapper mmStockTransferMapper;
    @Autowired
    private MmStockTransferDetailMapper mmStockTransferDetailMapper;
    @Autowired
    private IMmMaterialStockService mmMaterialStockService;
    @Autowired
    private IMdmCodeRuleService mdmCodeRuleService;
    @Autowired
    private IMdmMovementTypeService mdmMovementTypeService;
    @Autowired
    private IMmStockInOutService mmStockInOutService;

    @Override
    @Transactional
    public void saveMain(MmStockTransfer mmStockTransfer, List<MmStockTransferDetail> mmStockTransferDetailList) throws Exception {
        mmStockTransferMapper.insert(mmStockTransfer);
        if (mmStockTransferDetailList != null && mmStockTransferDetailList.size() > 0) {
            for (MmStockTransferDetail entity : mmStockTransferDetailList) {
                //外键设置
                entity.setPid(mmStockTransfer.getId());
                entity.setTransferQty(entity.getBillQty());
                mmStockTransferDetailMapper.insert(entity);

                //更新库存分配
                MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
                stockAllocateModel.setMaterialId(entity.getMaterialId());
                stockAllocateModel.setWarehouseId(mmStockTransfer.getWarehouseOut());
                stockAllocateModel.setStorageLocationId(entity.getStorageLocationOut());
                stockAllocateModel.setBatchNo(entity.getBatchOut());
                stockAllocateModel.setOldQty(BigDecimal.ZERO);
                stockAllocateModel.setNewQty(entity.getBillQty());
                mmMaterialStockService.updateStockAllocate(stockAllocateModel);
            }
        }

    }

    @Override
    @Transactional
    public void updateMain(MmStockTransfer mmStockTransfer, List<MmStockTransferDetail> mmStockTransferDetailList) throws Exception {
        MmStockTransfer mmStockTransferOld = mmStockTransferMapper.selectById(mmStockTransfer.getId());
        if (!"01".equals(mmStockTransferOld.getStatus())) {
            throw new RuntimeException("单据当前状态不能修改");
        }
        mmStockTransferMapper.updateById(mmStockTransfer);

        // 子表数据处理
        List<MmStockTransferDetail> stockTransferDetailOldList = mmStockTransferDetailMapper.selectByMainId(mmStockTransfer.getId());
        //1.子表数据新增/修改
        if (mmStockTransferDetailList != null && mmStockTransferDetailList.size() > 0) {
            Map<String, MmStockTransferDetail> idAndData = stockTransferDetailOldList.stream().collect(Collectors.toMap(MmStockTransferDetail::getId, transferDetail->transferDetail));
            for (MmStockTransferDetail entity : mmStockTransferDetailList) {
                MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
                stockAllocateModel.setMaterialId(entity.getMaterialId());
                stockAllocateModel.setWarehouseId(mmStockTransfer.getWarehouseOut());
                stockAllocateModel.setStorageLocationId(entity.getStorageLocationOut());
                stockAllocateModel.setBatchNo(entity.getBatchOut());
                if (!idAndData.containsKey(entity.getId())) {
                    //新增
                    entity.setPid(mmStockTransfer.getId());
                    entity.setTransferQty(entity.getBillQty());
                    mmStockTransferDetailMapper.insert(entity);
                    //分配库存
                    stockAllocateModel.setOldQty(BigDecimal.ZERO);
                    stockAllocateModel.setNewQty(entity.getBillQty());
                } else {
                    //修改
                    entity.setTransferQty(entity.getBillQty());
                    mmStockTransferDetailMapper.updateById(entity);
                    //分配库存
                    stockAllocateModel.setOldQty(idAndData.get(entity.getId()).getBillQty());
                    stockAllocateModel.setNewQty(entity.getBillQty());
                }
                //更新库存分配
                mmMaterialStockService.updateStockAllocate(stockAllocateModel);
            }
        }
        // 2.子表数据删除
        List<String> detailIdUpdList = mmStockTransferDetailList.stream().map(MmStockTransferDetail::getId).collect(Collectors.toList());
        for (MmStockTransferDetail transferDetailOld : stockTransferDetailOldList) {
            if (!detailIdUpdList.contains(transferDetailOld.getId())) {
                //删除
                mmStockTransferDetailMapper.deleteById(transferDetailOld.getId());
                //更新库存分配
                MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
                stockAllocateModel.setMaterialId(transferDetailOld.getMaterialId());
                stockAllocateModel.setWarehouseId(mmStockTransferOld.getWarehouseOut());
                stockAllocateModel.setStorageLocationId(transferDetailOld.getStorageLocationOut());
                stockAllocateModel.setBatchNo(transferDetailOld.getBatchOut());
                stockAllocateModel.setOldQty(transferDetailOld.getBillQty());
                stockAllocateModel.setNewQty(BigDecimal.ZERO);
                mmMaterialStockService.updateStockAllocate(stockAllocateModel);
            }
        }
    }

    @Override
    @Transactional
    public void delMain(String id) throws Exception {
        MmStockTransfer mmStockTransfer = mmStockTransferMapper.selectById(id);
        if (!mmStockTransfer.getStatus().equals("01")) {
            throw new RuntimeException("当前状态不能删除");
        }
        // 更新库存分配
        MmStockTransferDetailPage mmStockTransferDetailPage = new MmStockTransferDetailPage();
        mmStockTransferDetailPage.setPid(id);
        List<MmStockTransferDetailModel> mmStockTransferDetailList = mmStockTransferDetailMapper.selectDetailList(null, mmStockTransferDetailPage,null);
        for (MmStockTransferDetailModel transferDetailModel : mmStockTransferDetailList) {
            MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
            stockAllocateModel.setMaterialId(transferDetailModel.getMaterialId());
            stockAllocateModel.setWarehouseId(mmStockTransfer.getWarehouseOut());
            stockAllocateModel.setStorageLocationId(transferDetailModel.getStorageLocationOut());
            stockAllocateModel.setBatchNo(transferDetailModel.getBatchOut());
            stockAllocateModel.setOldQty(transferDetailModel.getBillQty());
            stockAllocateModel.setNewQty(BigDecimal.ZERO);
            mmMaterialStockService.updateStockAllocate(stockAllocateModel);
        }
        mmStockTransferDetailMapper.deleteByMainId(id);
        mmStockTransferMapper.deleteById(id);
    }

    @Override
    @Transactional
    public void delBatchMain(Collection<? extends Serializable> idList) throws Exception {
        for (Serializable id : idList) {
            delMain((String) id);
        }
    }

    /**
     * 明细分页查询
     *
     * @param page
     * @param detailPage
     * @return void
     * @throws
     */
    @Override
    public void detailPage(Page<MmStockTransferDetailModel> page, MmStockTransferDetailPage detailPage) {
        String sql = QueryGenerator.installAuthJdbc(MmStockTransfer.class);
        page.setRecords(mmStockTransferDetailMapper.selectDetailList(page, detailPage,sql));
    }

    /**
     * 明细列表查询
     *
     * @param detailPage
     * @return void
     * @throws
     */
    @Override
    public List<MmStockTransferDetailModel> detailList(MmStockTransferDetailPage detailPage) {
        String sql = QueryGenerator.installAuthJdbc(MmStockTransfer.class);
        return mmStockTransferDetailMapper.selectDetailList(null, detailPage,sql);
    }

    /**
     * 调入确认
     *
     * @param mmStockTransferPageList
     * @return void
     * @throws Exception
     */
    @Transactional
    @Override
    public void confirmDetail(List<MmStockTransferDetailPage> mmStockTransferPageList) throws Exception {
        if (oConvertUtils.listIsEmpty(mmStockTransferPageList)) {
            throw new RuntimeException("调拨数据为空");
        }
        Date now = new Date();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<String> idList = mmStockTransferPageList.stream().map(MmStockTransferDetailPage::getId).collect(Collectors.toList());
        //确认前数据
        QueryWrapper<MmStockTransferDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id",idList);
        List<MmStockTransferDetail> dataList = mmStockTransferDetailMapper.selectList(queryWrapper);
        Map<String, MmStockTransferDetail> idAndData = dataList.stream().collect(Collectors.toMap(MmStockTransferDetail::getId, data -> data));
        //
        Map<String, List<MmStockTransferDetailPage>> pidAndDataPageList = mmStockTransferPageList.stream().collect(Collectors.groupingBy(MmStockTransferDetailPage::getPid));
        for(String pid : pidAndDataPageList.keySet()){
            List<MmStockTransferDetailPage> dataPageList = pidAndDataPageList.get(pid);
            for (MmStockTransferDetailPage dataPage : dataPageList) {
                MmStockTransferDetail data = idAndData.get(dataPage.getId());
                if(data == null){
                    throw new RuntimeException("数据未找到："+ dataPage.getBillNo() + ":" + dataPage.getLineNo());
                }
                if( "1".equals(data.getConfirmFlag())){
                    throw new RuntimeException("已调入确认的单据不能修改："+ dataPage.getBillNo() + ":" + dataPage.getLineNo());
                }
                MmStockTransferDetail transferDetailModify = new MmStockTransferDetail();
                BeanUtils.copyProperties(dataPage, transferDetailModify);
                transferDetailModify.setConfirmFlag("1");
                transferDetailModify.setConfirmDate(now);
                transferDetailModify.setConfirmEmp(sysUser.getUsername());
                mmStockTransferDetailMapper.updateById(transferDetailModify);
                //更新库存分配量
                MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
                stockAllocateModel.setMaterialId(dataPage.getMaterialId());
                stockAllocateModel.setWarehouseId(dataPage.getWarehouseOut());
                stockAllocateModel.setStorageLocationId(dataPage.getStorageLocationOut());
                stockAllocateModel.setBatchNo(dataPage.getBatchOut());
                stockAllocateModel.setOldQty(data.getBillQty());
                stockAllocateModel.setNewQty(dataPage.getTransferQty());
                mmMaterialStockService.updateStockAllocate(stockAllocateModel);
            }
            //生成出入库单据
            List<Map<MmStockInOut, List<MmStockInOutDetail>>> stockInOutMapList = generateStockInOut(dataPageList);
            for(Map<MmStockInOut, List<MmStockInOutDetail>> stockInOutMap: stockInOutMapList ){
                Set<Map.Entry<MmStockInOut, List<MmStockInOutDetail>>> entries = stockInOutMap.entrySet();
                for(Map.Entry<MmStockInOut, List<MmStockInOutDetail>> entry : entries){
                    mmStockInOutService.saveMain(entry.getKey(), entry.getValue());
                }
            }
            //更新调拨主表状态
            queryWrapper.clear();
            queryWrapper.eq("pid", pid);
            int sumCount = mmStockTransferDetailMapper.selectCount(queryWrapper);
            queryWrapper.eq("confirm_flag", "1");
            int confirmCount = mmStockTransferDetailMapper.selectCount(queryWrapper);
            if(confirmCount > 0){
                MmStockTransfer mmStockTransferModify = new MmStockTransfer();
                mmStockTransferModify.setId(pid);
                if(confirmCount < sumCount){
                    mmStockTransferModify.setStatus(StockTransferStatus.STATUS_02);
                }else{
                    mmStockTransferModify.setStatus(StockTransferStatus.STATUS_03);
                }
                mmStockTransferMapper.updateById(mmStockTransferModify);
            }
        }
    }

    @Transactional
    @Override
    public void delDetailBatch(List<String> idList) throws Exception {
        QueryWrapper<MmStockTransferDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("id", idList);
        List<MmStockTransferDetail> dataList = mmStockTransferDetailMapper.selectList(queryWrapper);
        long count = dataList.stream().filter(data -> data.getConfirmFlag().equals("1")).count();
        if(count > 0){
            throw new RuntimeException("已调入单据不能删除");
        }
        for(MmStockTransferDetail data : dataList){
            //更新库存分配
            MmStockTransfer mmStockTransfer = mmStockTransferMapper.selectById(data.getPid());
            MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
            stockAllocateModel.setMaterialId(data.getMaterialId());
            stockAllocateModel.setWarehouseId(mmStockTransfer.getWarehouseOut());
            stockAllocateModel.setStorageLocationId(data.getStorageLocationOut());
            stockAllocateModel.setBatchNo(data.getBatchOut());
            stockAllocateModel.setOldQty(data.getBillQty());
            stockAllocateModel.setNewQty(BigDecimal.ZERO);
            mmMaterialStockService.updateStockAllocate(stockAllocateModel);
            //删除
            mmStockTransferDetailMapper.deleteById(data.getId());
        }
    }

    @Transactional
    @Override
    public void delDetail(String id) throws Exception {

        MmStockTransferDetail data = mmStockTransferDetailMapper.selectById(id);
        if(data.getConfirmFlag().equals("1")){
            throw new RuntimeException("已调入单据不能删除");
        }
        //更新库存分配
        MmStockTransfer mmStockTransfer = mmStockTransferMapper.selectById(data.getPid());
        MmMaterialStockAllocateModel stockAllocateModel = new MmMaterialStockAllocateModel();
        stockAllocateModel.setMaterialId(data.getMaterialId());
        stockAllocateModel.setWarehouseId(mmStockTransfer.getWarehouseOut());
        stockAllocateModel.setStorageLocationId(data.getStorageLocationOut());
        stockAllocateModel.setBatchNo(data.getBatchOut());
        stockAllocateModel.setOldQty(data.getBillQty());
        stockAllocateModel.setNewQty(BigDecimal.ZERO);
        mmMaterialStockService.updateStockAllocate(stockAllocateModel);
        //删除
        mmStockTransferDetailMapper.deleteById(data.getId());
    }

    private List<Map<MmStockInOut, List<MmStockInOutDetail>>> generateStockInOut(List<MmStockTransferDetailPage> dataPageList){
        Date now = new Date();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //移动类型
        String moveInId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE313);
        String moveOutId = mdmMovementTypeService.findIdByTypeNo(MdmConstant.MOVE_TYPE314);
        //出入库单据
        List<Map<MmStockInOut, List<MmStockInOutDetail>>> stockInOutList = new ArrayList<>();
        Map<MmStockInOut, List<MmStockInOutDetail>> stockInMap = new HashMap<>();
        Map<MmStockInOut, List<MmStockInOutDetail>> stockOutMap = new HashMap<>();
        //入库单主表
        MmStockInOut mmStockIn = new MmStockInOut();
        mmStockIn.setId(UUIDGenerator.generate());
        mmStockIn.setBillNo(mdmCodeRuleService.generateStockInOutCode());
        mmStockIn.setBillDate(now);
        mmStockIn.setCreateBy(sysUser.getUsername());
        mmStockIn.setCreateTime(now);
        mmStockIn.setSysOrgCode(sysUser.getOrgCode());
        mmStockIn.setWarehouseId(dataPageList.get(0).getWarehouseIn());
        mmStockIn.setIoFlag("i");
        mmStockIn.setMoveId(moveInId);
        //出库主表
        MmStockInOut mmStockOut = new MmStockInOut();
        mmStockOut.setId(UUIDGenerator.generate());
        mmStockOut.setBillNo(mdmCodeRuleService.generateStockInOutCode());
        mmStockOut.setBillDate(now);
        mmStockOut.setCreateBy(sysUser.getUsername());
        mmStockOut.setCreateTime(now);
        mmStockOut.setSysOrgCode(sysUser.getOrgCode());
        mmStockOut.setWarehouseId(dataPageList.get(0).getWarehouseOut());
        mmStockOut.setIoFlag("o");
        mmStockOut.setMoveId(moveOutId);
        //
        List<MmStockInOutDetail> stockInDetailList = new ArrayList<>();
        List<MmStockInOutDetail> stockOutDetailList = new ArrayList<>();
        int seq = 1;
        for(MmStockTransferDetailPage detailPage : dataPageList){
            //入库明细
            MmStockInOutDetail stockInDetail = new MmStockInOutDetail();
            stockInDetail.setId(UUIDGenerator.generate());
            stockInDetail.setPid(mmStockIn.getId());
            stockInDetail.setLineNo((seq++)*10);
            stockInDetail.setMaterialId(detailPage.getMaterialId());
            stockInDetail.setMaterialNo(detailPage.getMaterialNo());
            stockInDetail.setMaterialDesc(detailPage.getMaterialDesc());
            stockInDetail.setUnit(detailPage.getUnit());
            stockInDetail.setQty(detailPage.getTransferQty());
            stockInDetail.setUnitPrice(detailPage.getUnitPrice());
            stockInDetail.setSumPrice(detailPage.getSumPrice());
            stockInDetail.setSourceId(detailPage.getId());
            stockInDetail.setSourceNo(detailPage.getBillNo());
            stockInDetail.setBatchNo(detailPage.getBatchIn());
            stockInDetail.setWarehouseId(detailPage.getWarehouseIn());
            stockInDetail.setStorageLocationId(detailPage.getStorageLocationIn());
            stockInDetail.setCreateBy(sysUser.getUsername());
            stockInDetail.setCreateTime(now);
            stockInDetail.setSysOrgCode(sysUser.getOrgCode());
            stockInDetailList.add(stockInDetail);
            //出库明细
            MmStockInOutDetail stockOutDetail = new MmStockInOutDetail();
            BeanUtils.copyProperties(stockInDetail, stockOutDetail);
            stockOutDetail.setId(UUIDGenerator.generate());
            stockOutDetail.setPid(mmStockOut.getId());
            stockOutDetail.setBatchNo(detailPage.getBatchOut());
            stockOutDetail.setWarehouseId(detailPage.getWarehouseOut());
            stockOutDetail.setStorageLocationId(detailPage.getStorageLocationOut());
            stockOutDetailList.add(stockOutDetail);
        }

        stockInMap.put(mmStockIn, stockInDetailList);
        stockOutMap.put(mmStockOut, stockOutDetailList);
        stockInOutList.add(stockInMap);
        stockInOutList.add(stockOutMap);

        return stockInOutList;
    }

}
